//
//  ICSocketCommunicationManager.m
//  ICome
//
//  Created by zhangrongwu on 16/8/4.
//  Copyright © 2016年 iCom. All rights reserved.
//

#import "ICSocketCommunicationManager.h"
#import "ICAsyncSocketManager.h"
#import "ICAsyncSocketConfig.h"
#import "ICTCPrequestPackage.h"
#import "ICHeaderFile.h"
#import "iComeApiManager.h"
#define Timeout 30
@interface ICSocketCommunicationManager()

@end
@implementation ICSocketCommunicationManager
+(nullable ICSocketCommunicationManager *)sharedInstance {
    static ICSocketCommunicationManager *instance = nil;
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        instance = [[ICSocketCommunicationManager alloc] init];
    });
    return instance;
}

-(instancetype)init {
    if (self = [super init]) {
        self.requestsMap = [[NSMutableDictionary alloc] init];
        self.requestsList = [[NSMutableArray alloc] init];
        
    }
    return self;
}

-(void)requestWithRequestType:(SocketType)type
                  requestBody:(NSDictionary *)body
                   Identifier:(NSString *)identifier
                   completion:(SocketDidReadBlock)callback {
    NSString *blockRequestIdentifier = identifier;
    if ([identifier isEqualToString:@"0"]) {
        blockRequestIdentifier = [self creatRequestIdentifier];
    }
    
    if (callback) { // 把对应回调保存到字典中
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.requestsMap setValue:callback forKey:blockRequestIdentifier];
            [self registerRequestTimeout:blockRequestIdentifier];
            /**
             *  !. 消息发送者 定义了identifier  -- >>> 系统不进行主动发送请求 -- >> 否则系统
             *  1. 保存 任意一次请求
             *  2. 重连 tcp重新连接
             *  3. 发送 连接成功后发送 被保存的失败请求
             */
            
            ICTCPrequestPackage *request = [[ICTCPrequestPackage alloc] init];
            request.body = body;
            request.identifier = blockRequestIdentifier;
            [self.requestsList addObject:request];
            //            if ([identifier isEqualToString:@"0"]) {
            //                ICTCPrequestPackage *request = [[ICTCPrequestPackage alloc] init];
            //                request.body = body;
            //                request.identifier = blockRequestIdentifier;
            //                [self.requestsList addObject:request];
            //            }
        });
    }
    
    //    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0) , ^{
    //        NSLog(@"thread-info:%@开始执行任务",[NSThread currentThread]);
    //        [[ICAsyncSocketManager sharedInstance] socketRequestWithRequestBody:[self setIdentifier:blockRequestIdentifier Object:body] requestTag:0];
    //    });
    
    dispatch_async(YYDispatchQueueGetForQOS(NSQualityOfServiceBackground), ^{
        [[ICAsyncSocketManager sharedInstance] socketRequestWithRequestBody:[self setIdentifier:blockRequestIdentifier Object:body] requestTag:0];
    });
}

// 部分业务需求重新发送数据
- (void)reSendRequest {
    [self.requestsList enumerateObjectsUsingBlock:^(ICTCPrequestPackage *pakge, NSUInteger idx, BOOL * _Nonnull stop) {
        
        if ([self.requestsMap containsObjectForKey:pakge.identifier]) {
            
            [[ICAsyncSocketManager sharedInstance] socketRequestWithRequestBody:[self setIdentifier:pakge.identifier Object:pakge.body] requestTag:0];
            NSLog(@"reSend  request");
        }
    }];
}

// creat request identifier
- (NSString *)creatRequestIdentifier {
    NSInteger timeInterval = [NSDate date].timeIntervalSince1970 * 1000000;
    NSInteger requestIdentifier = timeInterval + arc4random() % 100000;
    return [NSString stringWithFormat:@"%ld", requestIdentifier] ;
}


/**
 *  设置 Identifier
 *  由于asycnsocket封装的tag基于进栈出栈方式
 *  还是无法具体区分某个tcp请求
 *  所以才用旧的服务器回调方式来区分每个请求
 *
 *  @param object request param
 *
 *  @return have identifier request param
 */
- (NSDictionary *)setIdentifier:(NSString *)identifier Object:(id)object  {
    NSString *path = [object objectForKey:@"p"];
    NSString *identifierPath = [NSString stringWithFormat:@"%@#%@", path, identifier];
    [object setValue:identifierPath forKey:@"p"];
    return object;
}

//  register timeout
- (void)registerRequestTimeout:(NSString *)requestIdentifier {
    double delayInSeconds = Timeout;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^{
        
        SocketDidReadBlock didreadBlock = self.requestsMap[requestIdentifier];
        NSDictionary *userInfo = @{@"identify":requestIdentifier,
                                   @"command":@""};
        NSError* error = [NSError errorWithDomain:@"请求超时" code:0 userInfo:userInfo];
        if (didreadBlock) {
            didreadBlock(nil, error, userInfo);
        }
        [self finishRequest:requestIdentifier];
    });
}


// remove request identifier
- (void)finishRequest:(NSString *)request {
    [self.requestsMap removeObjectForKey:request];
    if ([self.requestsMap count] == 0) {
        [self.requestsList enumerateObjectsUsingBlock:^(ICTCPrequestPackage *failRequest, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([failRequest.identifier isEqualToString:request]) {
                [self.requestsList removeObject:failRequest];
            }
        }];
    }
}


/**
 *  receive server data
 *
 *  @param data       request back data
 *  @param identifier call back identifier
 */
- (void)receiveServerData:(NSData*)data callbackIdentifier:(NSInteger)identifier {
    NSError *jsonError;
    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonError];
    
    NSDictionary *dataDict = [json objectForKey:@"d"];
    NSInteger c = [[json objectForKey:@"c"] integerValue];
    NSString *p = [json objectForKey:@"p"];
    
    
    if (c == ICConnectCmdType_LocFuncBack || c == ICConnectCmdType_LongDistanceFuncBack) {
        NSArray *blocks = [p componentsSeparatedByString:@"#"];
        NSString *blockRequestIdentifier = [blocks lastObject];
        SocketDidReadBlock didreadBlock = self.requestsMap[blockRequestIdentifier];
        
        
        // 由Client发起的请求 进入对应回调
        if (c < 100) { // 通讯层成功
            NSString *errorMsg = @"";
            if (![ICTools stringEmpty:dataDict[@"error"]]) {
                errorMsg = dataDict[@"error"];
            }
            NSString *msg = [dataDict[@"errno"] integerValue] != 0 ? errorMsg : @"";
            NSDictionary *userInfo = @{@"identify":blockRequestIdentifier,
                                       @"command":[json objectForKey:@"c"]};
            NSError* error = [NSError errorWithDomain:msg code:0 userInfo:nil];
            
            
            @try {
                if (didreadBlock) {
                    didreadBlock(dataDict, error, userInfo);
                    [self finishRequest:blockRequestIdentifier];
                }
            }
            @catch (NSException *exception) {
                NSString *errIdentifier = [NSString stringWithFormat:@"completion response is error（一般为block回调里数据解析出错） identifier : %@", p];
                NSLog(@"%@", errIdentifier);
            }
        } else {
            
            NSDictionary *userInfo = @{@"identify":blockRequestIdentifier,
                                       @"command":[json objectForKey:@"c"]};
            NSError *error = [NSError errorWithDomain:@"服务器错误" code:1001 userInfo:nil];
            if (didreadBlock) {
                didreadBlock(nil, error, userInfo);
                [self finishRequest:blockRequestIdentifier];
            }
        }
        
    } else {
        // 接收消息
        if (c < 100) {
            
            if (c != ICConnectCmdType_HeartBeatBack) {
                if (c == ICConnectCmdType_None) {
                    NSString *userName = [[NSUserDefaults standardUserDefaults] objectForKey:@"iComeApiManagerUserName"];
                    NSString *passWord = [[NSUserDefaults standardUserDefaults] objectForKey:@"iComeApiManagerPassWord"];
                    BOOL server = [[NSUserDefaults standardUserDefaults] integerForKey:@"iComeApiManagerIsDebug"];

                    [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"Token"];
                    [[iComeApiManager instance] regiserApiUserName:userName passWord:passWord server:server :nil :nil];
                } else {
                    if (![ICTools isObjEmpty:dataDict]) {
                        NSDictionary *userInfo = @{@"command":[json objectForKey:@"c"]};
                        /**
                         *  后台返回消息标识
                         *  根据消息标识 把消息分发到具体某个界面
                         */
                        [ICNotification postNotificationName:NotificationReceiveMessage object:dataDict userInfo:userInfo];
                        
                        NSLog(@"receive message : %@", dataDict);
                    } else {
                        NSLog(@"connect :  %@", json);
                    }
                }
            }
        }
    }
}

@end

